﻿using System;
using System.Globalization;

namespace CoreRay
{
    [Serializable]
    public class BoundingBox
    {
        public static readonly BoundingBox Empty = new BoundingBox();


        public BoundingBox() : this(new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity), new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity))
        {
        }

		public BoundingBox(Vector3 minPoint, Vector3 maxPoint)
		{
			this.MinPoint = minPoint;
			this.MaxPoint = maxPoint;
		}


        public Vector3 MinPoint
        {
            get;
            private set;
        }

        public Vector3 MaxPoint
        {
            get;
            private set;
        }

		public Vector3 Size
		{
			get
			{
				return this.MaxPoint - this.MinPoint;
			}
		}


		public float XSize
		{
			get
			{
                return this.MaxPoint.X - this.MinPoint.X;
			}
		}

		public float YSize
		{
			get
			{
                return this.MaxPoint.Y - this.MinPoint.Y;
			}
		}

		public float ZSize
		{
			get
			{
                return this.MaxPoint.Z - this.MinPoint.Z;
			}
		}


		public Vector3 Center
		{
			get
			{
                return (this.MinPoint + this.MaxPoint) * 0.5f;
			}
		}


		public bool IsEmpty
		{
			get
			{
                return (this.MinPoint.X > this.MaxPoint.X) || (this.MinPoint.Y > this.MaxPoint.Y) || (this.MinPoint.Z > this.MaxPoint.Z);
			}
		}


		public void Add(Vector3 point)
		{
			float minX = (point.X < this.MinPoint.X) ? point.X : this.MinPoint.X;
			float minY = (point.Y < this.MinPoint.Y) ? point.Y : this.MinPoint.Y;
			float minZ = (point.Z < this.MinPoint.Z) ? point.Z : this.MinPoint.Z;

			float maxX = (point.X > this.MaxPoint.X) ? point.X : this.MaxPoint.X;
			float maxY = (point.Y > this.MaxPoint.Y) ? point.Y : this.MaxPoint.Y;
			float maxZ = (point.Z > this.MaxPoint.Z) ? point.Z : this.MaxPoint.Z;
	
			this.MinPoint = new Vector3(minX, minY, minZ);
			this.MaxPoint = new Vector3(maxX, maxY, maxZ);
		}

        public void Add(BoundingBox value) 
        {
	        // Expand the box as necessary
            float minX = (value.MinPoint.X < MinPoint.X) ? value.MinPoint.X : this.MinPoint.X;
            float minY = (value.MinPoint.Y < MinPoint.Y) ? value.MinPoint.Y : this.MinPoint.Y;
            float minZ = (value.MinPoint.Z < MinPoint.Z) ? value.MinPoint.Z : this.MinPoint.Z;

            float maxX = (value.MaxPoint.X > MaxPoint.X) ? value.MaxPoint.X : this.MaxPoint.X;
            float maxY = (value.MaxPoint.Y > MaxPoint.Y) ? value.MaxPoint.Y : this.MaxPoint.Y;
            float maxZ = (value.MaxPoint.Z > MaxPoint.Z) ? value.MaxPoint.Z : this.MaxPoint.Z;

            this.MinPoint = new Vector3(minX, minY, minZ);
            this.MaxPoint = new Vector3(maxX, maxY, maxZ);
        }

        public bool Contains(Vector3 point)
        {
            return (point.X >= this.MinPoint.X) && (point.X <= this.MaxPoint.X) && (point.Y >= this.MinPoint.Y) && (point.Y <= this.MaxPoint.Y) && (point.Z >= this.MinPoint.Z) && (point.Z <= this.MaxPoint.Z);
        }

        public bool Intersect(Ray ray)
        {
            if (this.Contains(ray.Origin))
            {
                return true;
            }

            switch (ray.SlopeInfo.SlopeType)
            {
                case RaySlopeType.MMM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MMP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MPM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MPP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PMM:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PMP:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PPM:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PPP:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.OMM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.OMP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.OPM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.OPP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MOM:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MOP:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.POM:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.POP:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MMO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MPO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PMO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.PPO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        )
                        return false;

                    return true;

                case RaySlopeType.MOO:

                    if ((ray.Origin.X < this.MinPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return false;

                    return true;

                case RaySlopeType.POO:

                    if ((ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return false;

                    return true;

                case RaySlopeType.OMO:

                    if ((ray.Origin.Y < this.MinPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return false;

                    return true;

                case RaySlopeType.OPO:

                    if ((ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return false;

                    return true;

                case RaySlopeType.OOM:

                    if ((ray.Origin.Z < this.MinPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        )
                        return false;

                    return true;

                case RaySlopeType.OOP:

                    if ((ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        )
                        return false;

                    return true;

            }

            return false;
        }


        public float IntersectDistance(Ray ray)
        {
            float distance = 0.0f;
            float t1;
            float t2;

            if (this.Contains(ray.Origin))
            {
                return 0.1f;
            }

            switch (ray.SlopeInfo.SlopeType)
            {
                case RaySlopeType.MMM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MMP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MPM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MPP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.PMM:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.PMP:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.PPM:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.PPP:

                    if ((ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.OMM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.OMP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY > 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MinPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.OPM:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MinPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ > 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.OPP:

                    if ((ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y > this.MaxPoint.Y) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeZY * this.MaxPoint.Z - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantZY < 0)
                        || (ray.SlopeInfo.SlopeYZ * this.MaxPoint.Y - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantYZ < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MOM:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MOP:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MinPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantZX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.POM:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Z < this.MinPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MaxPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ > 0)
                        || (ray.SlopeInfo.SlopeZX * this.MinPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t2 = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.POP:

                    if ((ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.SlopeInfo.SlopeXZ * this.MaxPoint.X - this.MinPoint.Z + ray.SlopeInfo.BoundingBoxConstantXZ < 0)
                        || (ray.SlopeInfo.SlopeZX * this.MaxPoint.Z - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantZX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t2 = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    if (t2 > distance)
                        distance = t2;

                    return distance;

                case RaySlopeType.MMO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y < this.MinPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;

                    return distance;

                case RaySlopeType.MPO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MinPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MaxPoint.X + ray.SlopeInfo.BoundingBoxConstantYX > 0)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;

                    return distance;

                case RaySlopeType.PMO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y < this.MinPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MaxPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY > 0)
                        || (ray.SlopeInfo.SlopeYX * this.MinPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;

                    return distance;

                case RaySlopeType.PPO:

                    if ((ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X > this.MaxPoint.X) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.SlopeInfo.SlopeXY * this.MaxPoint.X - this.MinPoint.Y + ray.SlopeInfo.BoundingBoxConstantXY < 0)
                        || (ray.SlopeInfo.SlopeYX * this.MaxPoint.Y - this.MinPoint.X + ray.SlopeInfo.BoundingBoxConstantYX < 0)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    t1 = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    if (t1 > distance)
                        distance = t1;

                    return distance;

                case RaySlopeType.MOO:

                    if ((ray.Origin.X < this.MinPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    return distance;

                case RaySlopeType.POO:

                    if ((ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.X - ray.Origin.X) * ray.SlopeInfo.InverseDirectionX;
                    return distance;

                case RaySlopeType.OMO:

                    if ((ray.Origin.Y < this.MinPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    return distance;

                case RaySlopeType.OPO:

                    if ((ray.Origin.Y > this.MaxPoint.Y)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Z < this.MinPoint.Z) || (ray.Origin.Z > this.MaxPoint.Z)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.Y - ray.Origin.Y) * ray.SlopeInfo.InverseDirectionY;
                    return distance;

                case RaySlopeType.OOM:

                    if ((ray.Origin.Z < this.MinPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        )
                        return 0.0f;

                    distance = (this.MaxPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    return distance;

                case RaySlopeType.OOP:

                    if ((ray.Origin.Z > this.MaxPoint.Z)
                        || (ray.Origin.X < this.MinPoint.X) || (ray.Origin.X > this.MaxPoint.X)
                        || (ray.Origin.Y < this.MinPoint.Y) || (ray.Origin.Y > this.MaxPoint.Y)
                        )
                        return 0.0f;

                    distance = (this.MinPoint.Z - ray.Origin.Z) * ray.SlopeInfo.InverseDirectionZ;
                    return distance;

            }

            return 0.0f;
        }


        public static BoundingBox Add(BoundingBox boundingBox1, BoundingBox boundingBox2)
        {
            BoundingBox result = new BoundingBox(boundingBox1.MinPoint, boundingBox1.MaxPoint);

            result.Add(boundingBox2.MinPoint);
            result.Add(boundingBox2.MaxPoint);

            return result;
        }

        public static BoundingBox operator +(BoundingBox boundingBox1, BoundingBox boundingBox2)
        {
            return Add(boundingBox1, boundingBox2);
        }

        public override bool Equals(object obj)
		{
            if ((object) obj == null)
            {
                return false;
            }

			return obj is BoundingBox ? Equals((BoundingBox) obj) : false;
		}

		private bool Equals(BoundingBox boundingBox)
		{
            if ((object)boundingBox == null)
            {
                return false;
            }

            return this.MinPoint == boundingBox.MinPoint && this.MaxPoint == boundingBox.MaxPoint;
		}

		public static bool operator ==(BoundingBox aabb1, BoundingBox aabb2)
		{
            if ((object)aabb1 == null)
                return ((object)aabb2 == null);
            else
                return aabb1.Equals(aabb2);
		}

		public static bool operator !=(BoundingBox aabb1,BoundingBox aabb2)
		{
			return !aabb1.Equals(aabb2);
		}

		public override int GetHashCode()
		{
			return this.MinPoint.GetHashCode() ^ this.MaxPoint.GetHashCode();
		}

		public override string ToString()
		{
			return string.Format(CultureInfo.InvariantCulture, "({0}, {1})",this.MinPoint, this.MaxPoint);
		}
    }
}
